/*
 * PUBLIC DOMAIN PCCTS-BASED C++ GRAMMAR (cplusplus.g, stat.g, expr.g)
 *
 * Authors: Sumana Srinivasan, NeXT Inc.;            sumana_srinivasan@next.com
 *          Terence Parr, Parr Research Corporation; parrt@parr-research.com
 *          Russell Quong, Purdue University;        quong@ecn.purdue.edu
 *
 * VERSION 1.2
 *
 * SOFTWARE RIGHTS
 *
 * This file is a part of the ANTLR-based C++ grammar and is free
 * software.  We do not reserve any LEGAL rights to its use or
 * distribution, but you may NOT claim ownership or authorship of this
 * grammar or support code.  An individual or company may otherwise do
 * whatever they wish with the grammar distributed herewith including the
 * incorporation of the grammar or the output generated by ANTLR into
 * commerical software.  You may redistribute in source or binary form
 * without payment of royalties to us as long as this header remains
 * in all source distributions.
 *
 * We encourage users to develop parsers/tools using this grammar.
 * In return, we ask that credit is given to us for developing this
 * grammar.  By "credit", we mean that if you incorporate our grammar or
 * the generated code into one of your programs (commercial product,
 * research project, or otherwise) that you acknowledge this fact in the
 * documentation, research report, etc....  In addition, you should say nice
 * things about us at every opportunity.
 *
 * As long as these guidelines are kept, we expect to continue enhancing
 * this grammar.  Feel free to send us enhancements, fixes, bug reports,
 * suggestions, or general words of encouragement at parrt@parr-research.com.
 * 
 * NeXT Computer Inc.
 * 900 Chesapeake Dr.
 * Redwood City, CA 94555
 * 12/02/1994
 * 
 * Restructured for public consumption by Terence Parr late February, 1995.
 *
 * DISCLAIMER: we make no guarantees that this grammar works, makes sense,
 *             or can be used to do anything useful.
 */
/* 2001-2002
 * Version 1.0
 * This C++ grammar file has been converted from PCCTS to run under 
 *  ANTLR to generate lexer and parser in C++ code by
 *  Jianguo Zuo and David Wigg at
 *  The Centre for Systems and Software Engineering
 *  London South Bank University
 *  London, UK.
 *
 */
/* 2003
 * Version 2.0 was published by David Wigg in September 2003
 */
/* 2004
 * Version 3.0 July 2004
 * This is version 3.0 of the C++ grammar definition for ANTLR to 
 *  generate lexer and parser in C++ code updated by
 *  David Wigg at
 *  The Centre for Systems and Software Engineering
 *  London South Bank University
 *  London, UK.
 */
/* 2005
 * Version 3.1 November 2005
 * Updated by David Wigg at London South Bank University
 *
 */
/* 2007
 * Version 3.2 November 2007
 * Updated by David Wigg at London South Bank University
 *
 * wiggjd@bcs.ac.uk
 * blackse@lsbu.ac.uk
 *
 * See MyReadMe.txt for further information
 *
 * This file is best viewed in courier font with tabs set to 4 spaces
 */

header "pre_include_hpp"
	{// pre_include_hpp
	}

header "post_include_hpp"
	{// post_include_hpp
	}

header "pre_include_cpp"
	{// pre_include_cpp
	}

header "post_include_cpp"
	{// post_include_cpp
	}

header
	{
	// File generated from CPP_parser.g
	// Version 3.2 November 2007
	// This file is best viewed in courier font with tabs set to 4 spaces
	//
	// The statements in this block appear in both CPPLexer.hpp and CPPParser.hpp
	#include "antlr/CharScanner.hpp"
	#include "CPPDictionary.hpp"

	// Following externs declared here to be available for users

	// Declared and set in CPPParser.cpp
	extern int lineNo; // current line
	extern bool in_user_file;	// true = in principal file, false = in an include file

	// Declared and set in CPPLexer.cpp
	extern bool in_user_file_deferred;

	extern int deferredLineCount;	// used to accumulate line numbers in comments etc.

	extern char principal_file[128];	// Name of user file
	extern int principal_line;		// Principal file's line number
	extern int principal_last_set;	// Where principal file's line number was last set
									//   in preprocessed *.i file

	extern char current_included_file[128];	// Name of current include file
	extern int include_line;		// Included file's line number
	extern int include_last_set;	// Where included file's line number was last set
									//   in preprocessed *.i file

	// The statements in this block appear in both CPPLexer.hpp and CPPParser.hpp
	}

options
	{
	language = "Cpp";
	}

{
// File generated from CPP_parser.g
// Version 3.2 November 2007
// This file is best viewed in courier font with tabs set to 4 spaces
//
//	The statements in this block appear only in CPPParser.cpp

int statementTrace = 2;	// Used to control selected (level) tracing (see support.cpp)
						// 1 Shows which external and member statements selected
						// 2 Shows above plus all declarations/definitions
						// 3 reserved for future use
						// 4 and above available for user

void CPPParser::init()
	{
	antlrTrace(false);	// This is a dynamic trace facility for use with -traceParser etc.
						// It requires modification in LLkParser.cpp and LLkParser.hpp
						//  (Copies of these modified files are supplied with this code)
						//  otherwise it should be commented out (see MyReadMe.txt)
						// true shows antlr trace (or can be set and reset during parsing)
						// false stops showing antlr trace 
						// Provided the parser is always generated with -traceParser this
						//  facility allows trace output to be turned on or off just by changing
						//  the setting here from false to true or vice versa and then
						//  recompiling and linking CPPParser only thus avoiding the need
						//  to use antlr.Tool to re-generate the lexer and parser again
						//  with (or without) -traceParser each time before recompiling. 
						// Antlr trace can also be turned on and off dynamically using
						//  antlrTrace_on or antlrTrace_off statements inserted into the
						//  source code being parsed (See antlrTrace_on and antlrTrace_off below).
					
	// Creates a dictionary to hold symbols with 4001 buckets, 200 scopes and 800,000 characters
	// These can be changed to suit the size of program(s) being parsed
	symbols = new CPPDictionary(4001, 200, 800000);

	// Set template parameter scope - Not used at present
	templateParameterScope = symbols->getCurrentScopeIndex();	// Set template parameter scope to 0

	symbols->saveScope();	// Advance currentScope from 0 to 1
	// Set "external" scope for all types
	externalScope = symbols->getCurrentScopeIndex();	// Set "external" scope to 1 for types

	// Declare predefined scope "std" in external scope
	CPPSymbol *a = new CPPSymbol("std", CPPSymbol::otTypedef);
	symbols->define("std", a);

	symbols->saveScope();	// Advance currentScope from 1 to 2 (and higher) for all other symbols
							//  treated as locals

	// Global flags to allow for nested declarations
	_td = false;		// For typedef
	_fd = false;		// For friend
	_sc = scInvalid;	// For StorageClass
	_tq = tqInvalid;	// For TypeQualifier
	_ts = tsInvalid;	// For TypeSpecifier
	_fs = fsInvalid;	// For FunctionSpecifier

	functionDefinition = 0;
	qualifierPrefix[0] = '\0';
	enclosingClass = "";
	assign_stmt_RHS_found = 0;
	in_parameter_list = false;
	K_and_R = false;	// used to distinguish old K & R parameter definitions
	in_return = false;
	is_address = false;
	is_pointer = false;
	}	// End of CPPParser::init()

int lineNo = 0;
bool in_user_file;	// true = in principal file, false = in an include file
					// Set from in_user_file_deferred by external_declaration in CPP_parser.g

//	The statements in this block appear only in CPPParser.cpp
}

class CPPParser extends Parser;

options
	{
	k = 2;
	exportVocab = STDC;
	buildAST =false;
	codeGenMakeSwitchThreshold = 2;
	codeGenBitsetTestThreshold = 3;
	}

{	// These declarations go into CPPParser.hpp
public:
	#define CPPParser_MaxQualifiedItemSize 500

	// These codes are not stored with symbol names in CPPSymbol,
	//   but they are available for development
	// Can't bitwise-OR enum elements together, this must be an int; damn!
	typedef unsigned long TypeSpecifier;   // note: must be at least 16 bits
	#define tsInvalid   0x0
	#define tsVOID      0x1
	#define tsCHAR      0x2
	#define tsSHORT     0x4
	#define tsINT       0x8
	#define tsLONG      0x10
	#define tsFLOAT     0x20
	#define tsDOUBLE    0x40
	#define tsSIGNED    0x80
	#define tsUNSIGNED  0x100
	#define tsTYPEID    0x200
	#define tsSTRUCT    0x400
	#define tsENUM      0x800
	#define tsUNION     0x1000
	#define tsCLASS     0x2000
	#define tsWCHAR_T   0x4000
	#define tsBOOL      0x8000

	enum TypeQualifier 
		{ 
		tqInvalid=0, tqCONST=1, tqVOLATILE 
		};

	enum StorageClass 
		{
		scInvalid=0, scAUTO=1, scREGISTER,
		scSTATIC, scEXTERN, scMUTABLE
		};

	enum FunctionSpecifier 
		{
		fsInvalid=0,
		fsVIRTUAL, fsINLINE, fsEXPLICIT, fsFRIEND
		};

	typedef int QualifiedItem;
		#define qiInvalid     0x0
		#define qiType        0x1	// includes enum, class, typedefs, namespace
		#define qiDtor        0x2
		#define qiCtor        0x4
		#define qiOperator    0x8
		#define qiPtrMember   0x10
		#define qiVar         0x20
		#define qiFun         0x40

protected:
	// Symbol table management stuff
	CPPDictionary *symbols;
	int templateParameterScope;
	int externalScope;
	int anyType;
	int anyNonType;

	bool _td;			// For typedef
	bool _fd;			// For friend
	StorageClass _sc;	// For storage class
	TypeQualifier _tq;	// For type qualifier
	TypeSpecifier _ts;	// For type specifier
	FunctionSpecifier _fs;	// For declaration specifier
		
	int functionDefinition;	// 0 = Function definition not being parsed
							// 1 = Parsing function name
							// 2 = Parsing function parameter list
							// 3 = Parsing function block

	char qualifierPrefix[CPPParser_MaxQualifiedItemSize+1];
	char *enclosingClass;
	int assign_stmt_RHS_found;
	bool in_parameter_list;
	bool K_and_R;	// used to distinguish old K & R parameter definitions
	bool in_return;
	bool is_address;
	bool is_pointer;

	// Limit lookahead for qualifiedItemIs()
	enum 
		{ 
		MaxTemplateTokenScan = 200 
		};

public:
void init();

protected:
	// Semantic interface in Support.cpp; 
	// You could subclass and redefine these functions
	//  so you don't have to mess with the grammar itself.
	
	// Symbol stuff
	virtual int qualifiedItemIsOneOf(QualifiedItem qiFlags, int lookahead_offset=0);
	virtual QualifiedItem qualifiedItemIs(int lookahead_offset=0);
	virtual int skipTemplateQualifiers(int& kInOut);
	virtual int skipNestedParens(int& kInOut);
	virtual int scopedItem(int k=1);
	virtual int finalQualifier(const int k=1);
	virtual int isTypeName(const char *s);
	virtual int isClassName(const char *s);
	virtual void end_of_stmt();

	// Scoping stuff
	virtual void enterNewLocalScope();
	virtual void exitLocalScope();
	virtual void enterExternalScope();
	virtual void exitExternalScope();

	// Aggregate stuff
	virtual void classForwardDeclaration(const char *, TypeSpecifier, FunctionSpecifier);
	virtual void beginClassDefinition(const char *, TypeSpecifier);
	virtual void endClassDefinition();
	virtual void beginEnumDefinition(const char *);
	virtual void endEnumDefinition();
	virtual void enumElement(const char *);

	// Declaration and definition stuff
	virtual void declarationSpecifier(bool,bool,StorageClass,TypeQualifier,TypeSpecifier,FunctionSpecifier);
	virtual void beginDeclaration();
	virtual void endDeclaration();
	virtual void beginConstructorDeclaration(const char *);
	virtual void endConstructorDeclaration();
	virtual void beginDestructorDeclaration(const char *);
	virtual void endDestructorDeclaration();
	virtual void beginParameterDeclaration();
	virtual void beginFieldDeclaration();
	virtual void beginFunctionDefinition();
	virtual void endFunctionDefinition();
	virtual void functionParameterList();
	virtual void functionEndParameterList(const int def);
	virtual void beginConstructorDefinition();
	virtual void endConstructorDefinition();
	virtual void beginDestructorDefinition();
	virtual void endDestructorDefinition();

	// Declarator stuff
	virtual void declaratorID(const char *, QualifiedItem);	// This stores new symbol with its type.
	virtual void declaratorArray();
	virtual void declaratorParameterList(const int def);
	virtual void declaratorEndParameterList(const int def);

	// template stuff
	virtual void templateTypeParameter(const char *);
	virtual void beginTemplateDeclaration();
	virtual void endTemplateDeclaration();
	virtual void beginTemplateDefinition();
	virtual void endTemplateDefinition();
	virtual void beginTemplateParameterList();
	virtual void endTemplateParameterList();

	// exception stuff
	virtual void exceptionBeginHandler();
	virtual void exceptionEndHandler();
	virtual void panic(const char *);

	// myCode functions ready for overriding in MyCode subclass
	// Include application code functions here
	virtual void myCode_pre_processing(int, char *[]);
	virtual void myCode_post_processing();
	virtual void myCode_end_of_stmt();
	virtual void myCode_function_direct_declarator(const char *);
}

translation_unit
	:	{enterExternalScope();}
		(external_declaration)*  EOF
		{exitExternalScope();}
	;

//external_declaration	Note: These comment lines are provided to assist searching for productions
external_declaration
	{
	 char *s;
	 lineNo = LT(1)->getLine();
	 K_and_R = false;
	 FunctionSpecifier fs = fsInvalid;	// inline,virtual,explicit
	 in_user_file = in_user_file_deferred;
	}
	:  
	(
		// Template explicit specialisation
		("template" LESSTHAN GREATERTHAN)=>
		{if(statementTrace>=1) 
			printf("%d external_declaration template explicit-specialisation\n",LT(1)->getLine());
		}
		"template" LESSTHAN GREATERTHAN external_declaration
	|
		// All typedefs
		("typedef")=>
		(
			("typedef" "enum")=>
			{if(statementTrace>=1) 
				printf("%d external_declaration Typedef enum type\n",LT(1)->getLine());
			}
			"typedef" enum_specifier {_td = true;} (init_declarator_list)? SEMICOLON {end_of_stmt();}
		|
			(declaration_specifiers function_declarator[0] SEMICOLON)=>	// DW 11/02/05 This may not be possible
			{if(statementTrace>=1) 
				printf("%d external_declaration Typedef function type\n",LT(1)->getLine());
			}
			declaration
		|
			(declaration_specifiers (init_declarator_list)? SEMICOLON)=>
			{if(statementTrace>=1) 
				printf("%d external_declaration Typedef variable type\n",LT(1)->getLine());
			}
			declaration
		|
			("typedef" class_specifier)=>
			{if(statementTrace>=1) 
				printf("%d external_declaration Typedef class type\n",LT(1)->getLine());
			}
			"typedef" class_decl_or_def[fs] {_td = true;} (init_declarator_list)? SEMICOLON {end_of_stmt();}
		)
	|	
		// Class template declaration or definition
		(template_head (fs = function_specifier)* class_specifier)=>
		{if (statementTrace>=1) 
			printf("%d external_declaration Templated class decl or def\n",LT(1)->getLine());
		}
		template_head (fs = function_specifier)* class_decl_or_def[fs] (init_declarator_list)? SEMICOLON {end_of_stmt();}	// declaration
	|  
		// Enum definition (don't want to backtrack over this in other alts)
		("enum" (ID)? LCURLY)=>
		{if (statementTrace>=1) 
			printf("%d external_declaration Enum definition\n",LT(1)->getLine());
		}
		enum_specifier (init_declarator_list)? SEMICOLON {end_of_stmt();}
	|
		// Destructor definition (templated or non-templated)
		((template_head)? dtor_head[1] LCURLY)=>
		{if (statementTrace>=1) 
			printf("%d external_declaration Destructor definition\n",LT(1)->getLine());
		}
		(template_head)? dtor_head[1] dtor_body
	|  
		// Constructor definition (non-templated)
		// JEL 4/3/96 Added predicate that works, once the
		// restriction is added that ctor cannot be virtual
		// and ctor_declarator uses a more restrictive id
		(	(options {warnWhenFollowAmbig = false;}:
			 ctor_decl_spec)?
			{qualifiedItemIsOneOf(qiCtor)}?
		)=>
		{if (statementTrace>=1) 
			printf("%d external_declaration Constructor definition\n",LT(1)->getLine());
		}
		ctor_definition
	|  
		// User-defined type cast
		(("inline")? scope_override  conversion_function_decl_or_def)=>
		{if (statementTrace>=1) 
			printf("%d external_declaration Operator function\n",LT(1)->getLine());
		}
		("inline")? s = scope_override conversion_function_decl_or_def 
	|   
		// Function declaration
		(declaration_specifiers function_declarator[0] SEMICOLON)=> 
		{if (statementTrace>=1) 
			printf("%d external_declaration Function declaration\n",LT(1)->getLine());
		}
		declaration_specifiers function_declarator[0] SEMICOLON {end_of_stmt();}
	|
		// Function definition
		(declaration_specifiers	function_declarator[1] LCURLY)=> 
		{if (statementTrace>=1) 
			printf("%d external_declaration Function definition\n",LT(1)->getLine());
		}
		function_definition
	|
		// Function definition with int return assumed
		(function_declarator[1] LCURLY)=> 
		{if (statementTrace>=1) 
			printf("%d external_declaration Function definition without return type\n",LT(1)->getLine());
		}
		function_definition
	|
		// K & R Function definition
		(declaration_specifiers	function_declarator[1] declaration)=>
		{K_and_R = true;
		 if (statementTrace>=1) 
			printf("%d external_declaration K & R function definition\n",LT(1)->getLine());
		}
		function_definition
	|
		// K & R Function definition with int return assumed
		(function_declarator[1] declaration)=>
		{K_and_R = true;
		 if (statementTrace>=1) 
			printf("%d external_declaration K & R function definition without return type\n",LT(1)->getLine());
		}
		function_definition
	|
		// Class declaration or definition
		(("extern")? (fs = function_specifier)* class_specifier)=>
		{if (statementTrace>=1) 
			printf("%d external_declaration Class decl or def\n",LT(1)->getLine());
		}
		("extern")? (fs = function_specifier)* class_decl_or_def[fs] (init_declarator_list)? SEMICOLON {end_of_stmt();}
	|
		// Copied from member_declaration 31/05/07
		(declaration_specifiers (init_declarator_list)? SEMICOLON)=>
		{if (statementTrace>=1) 
			printf("%d external_declaration Declaration\n",LT(1)->getLine());
		}
		declaration
	|  
		// Templated functions and constructors matched here.
		{beginTemplateDeclaration();}
		template_head
		(  
			// templated forward class decl, init/decl of static member in template
			(declaration_specifiers (init_declarator_list)? SEMICOLON {end_of_stmt();})=>
			{if (statementTrace>=1) 
				printf("%d external_declaration Templated class forward declaration\n",LT(1)->getLine());
			}
			declaration_specifiers (init_declarator_list)? SEMICOLON {end_of_stmt();}
		|  
			// Templated function declaration
			(declaration_specifiers function_declarator[0] SEMICOLON)=> 
			{if (statementTrace>=1) 
				printf("%d external_declaration Templated function declaration\n",LT(1)->getLine());
			}
			declaration
		|  
			// Templated function definition
			(declaration_specifiers function_declarator[1] LCURLY)=> 
			{if (statementTrace>=1) 
				printf("%d external_declaration Templated function definition\n",LT(1)->getLine());
			}
			function_definition
		|
			// Templated constructor definition
            // JEL 4/3/96 Added predicate that works once the
            // restriction is added that ctor cannot be virtual
			(	ctor_decl_spec 
				{qualifiedItemIsOneOf(qiCtor)}?
			)=>
			{if (statementTrace>=1) 
				printf("%d external_declaration Templated constructor definition\n",LT(1)->getLine());
			}
			ctor_definition
		)
		{endTemplateDeclaration();}
	|  
		// Namespace definition
		{if (statementTrace>=1) 
			printf("%d external_declaration Namespace definition\n",LT(1)->getLine());
		}
		"namespace" namespace_definition
	|	
		// Semicolon
		{if (statementTrace>=1) 
			printf("%d external_declaration Semicolon\n",LT(1)->getLine());
		}
		SEMICOLON {end_of_stmt();}
	|	
		// Anything else 
		{if (statementTrace>=1) 
			printf("%d external_declaration Other Declaration\n",LT(1)->getLine());
		}
		declaration
	|	
		// The next two entries may be used for debugging
		// Use this statement in the source code to turn antlr trace on (See note above)
		"antlrTrace_on" {antlrTrace(true);}
	|
		// Use this statement in the source code to turn antlr trace off (See note above)
		"antlrTrace_off" {antlrTrace(false);}
	)
	;	// end of external_declaration

//namespace_definition
namespace_definition
	:
		(ns:ID{declaratorID((ns->getText()).data(),qiType);})?
		LCURLY 
		{enterNewLocalScope();}
		(external_declaration)*
		{exitLocalScope();}
		RCURLY
	;

//namespace_alias_definition
namespace_alias_definition
	{
	char *qid;
	}
	:
		"namespace"
		ns2:ID {declaratorID((ns2->getText()).data(),qiType);}
		ASSIGNEQUAL qid = qualified_id SEMICOLON {end_of_stmt();} 
	;

//member_declaration
member_declaration
	{
	char *q;
	lineNo = LT(1)->getLine();
	FunctionSpecifier fs = fsInvalid;	// inline,virtual,explicit
	}
	:
	(
		// Template explicit specialisation
		("template" LESSTHAN GREATERTHAN)=>
		{if(statementTrace>=1) 
			printf("%d member_declaration Template explicit-specialisation\n",LT(1)->getLine());
		}
		"template" LESSTHAN GREATERTHAN member_declaration
	|
		// All typedefs
		("typedef")=>
		(
			("typedef" "enum")=>
			{if(statementTrace>=1) 
				printf("%d member_declaration Typedef enum type\n",LT(1)->getLine());
			}
			"typedef" enum_specifier {_td = true;} (init_declarator_list)? SEMICOLON {end_of_stmt();}
		|
			(declaration_specifiers function_declarator[0] SEMICOLON)=>	// DW 11/02/05 This may not be possible member declaration
			{if(statementTrace>=1) 
				printf("%d member_declaration Typedef function type\n",LT(1)->getLine());
			}
			declaration
		|
			(declaration_specifiers (init_declarator_list)? SEMICOLON)=>
			{if(statementTrace>=1) 
				printf("%d member_declaration Typedef variable type\n",LT(1)->getLine());
			}
			declaration
		|
			("typedef" class_specifier)=>
			{if(statementTrace>=1) 
				printf("%d member_declaration Typedef class type\n",LT(1)->getLine());
			}
			"typedef" class_decl_or_def[fs] {_td = true;} (init_declarator_list)? SEMICOLON {end_of_stmt();}
		)
	|	
		// Templated class declaration or definition
		(template_head (fs = function_specifier)* class_specifier)=>
		{if (statementTrace>=1) 
			printf("%d member_declaration Templated class decl or def\n",LT(1)->getLine());
		}
		template_head (fs = function_specifier)* class_decl_or_def[fs] (init_declarator_list)? SEMICOLON {end_of_stmt();}	// declaration
	|  
		// Enum definition (don't want to backtrack over this in other alts)
		("enum" (ID)? LCURLY)=>
		{if (statementTrace>=1) 
			printf("%d member_declaration Enum definition\n",LT(1)->getLine());
		}
		enum_specifier (init_declarator_list)? SEMICOLON	{end_of_stmt();}
	|
		// Constructor declarator
		(	ctor_decl_spec
			{qualifiedItemIsOneOf(qiCtor)}?
			ctor_declarator[0] SEMICOLON
		)=>
		{if (statementTrace>=1) 
			printf("%d member_declaration Constructor declarator\n",LT(1)->getLine());
		}
		ctor_decl_spec ctor_declarator[0] SEMICOLON {end_of_stmt();}
	|  
		// JEL Predicate to distinguish ctor from function
		// This works now that ctor cannot have VIRTUAL
		// It unfortunately matches A::A where A is not enclosing
		// class -- this will have to be checked semantically
		// Constructor definition
		(	ctor_decl_spec
			{qualifiedItemIsOneOf(qiCtor)}?
			ctor_declarator[1]
			(COLON        // DEFINITION :ctor_initializer
			|LCURLY       // DEFINITION (compound Statement) ?
			)
		)=>
		{if (statementTrace>=1) 
			printf("%d member_declaration Constructor definition\n",LT(1)->getLine());
		}
		ctor_definition 
	|  
		// No template_head allowed for dtor member
		// Backtrack if not a dtor (no TILDE)
		// Destructor declaration
		(dtor_head[0] SEMICOLON)=>
		{if (statementTrace>=1) 
			printf("%d member_declaration Destructor declaration\n",LT(1)->getLine());
		}
		dtor_head[0] SEMICOLON {end_of_stmt();}
	|
		// No template_head allowed for dtor member
		// Backtrack if not a dtor (no TILDE)
		// Destructor definition
		(dtor_head[1] LCURLY)=>
		{if (statementTrace>=1) 
			printf("%d member_declaration Destructor definition\n",LT(1)->getLine());
		}
		dtor_head[1] dtor_body
	|
		// Function declaration
		(declaration_specifiers	function_declarator[0] SEMICOLON)=>
		{if (statementTrace>=1) 
			printf("%d member_declaration Function declaration\n",LT(1)->getLine());
		}
		declaration_specifiers function_declarator[0] SEMICOLON {end_of_stmt();}
	|  
		// Function definition
		(declaration_specifiers function_declarator[1] LCURLY)=>
		{if (statementTrace>=1) 
			printf("%d member_declaration Function definition\n",LT(1)->getLine());
		}
		function_definition
	|  
		// User-defined type cast
		(("inline")? conversion_function_decl_or_def)=>
		{if (statementTrace>=1) 
			printf("%d member_declaration Operator function\n",LT(1)->getLine());
		}
		("inline")? conversion_function_decl_or_def
	|  
		// Hack to handle decls like "superclass::member",
		// to redefine access to private base class public members
		// Qualified identifier
		(qualified_id SEMICOLON)=>
		{if (statementTrace>=1) 
			printf("%d member_declaration Qualified ID\n",LT(1)->getLine());
		}
		q = qualified_id SEMICOLON {end_of_stmt();}
	|
		// Class declaration or definition
		(("friend")? (fs = function_specifier)* class_specifier)=>
		{if (statementTrace>=1) 
			printf("%d member_declaration Class decl or def\n",LT(1)->getLine());
		}
		("friend")? (fs = function_specifier)* class_decl_or_def[fs] (init_declarator_list)? SEMICOLON {end_of_stmt();}
	|  
		(declaration_specifiers (init_declarator_list)? SEMICOLON)=>
		{if (statementTrace>=1) 
			printf("%d member_declaration Declaration\n",LT(1)->getLine());
		}
		declaration
	|  
		// Member without a type (I guess it can only be a function declaration or definition)
		((fs = function_specifier)* function_declarator[0] SEMICOLON)=>
		{fprintf(stderr,"%d warning Function declaration found without return type\n",LT(1)->getLine());
		 if (statementTrace>=1) 
			printf("%d member_declaration Function declaration\n",LT(1)->getLine());
		}
		(fs = function_specifier)* function_declarator[0] SEMICOLON {end_of_stmt();}
	|
		// Member without a type (I guess it can only be a function definition)
		((fs = function_specifier)* function_declarator[1] LCURLY)=>
		{fprintf(stderr,"%d warning Function definition found without return type\n",LT(1)->getLine());
		 if (statementTrace>=1) 
			printf("%d member_declaration Function definition without return type\n",LT(1)->getLine());
		}
		(fs = function_specifier)* function_declarator[1] compound_statement {endFunctionDefinition();}
	|  
		// Templated functions and constructors matched here.
		{beginTemplateDeclaration();}
		template_head
		(  
			// templated forward class decl, init/decl of static member in template
			(declaration_specifiers (init_declarator_list)? SEMICOLON)=>
			{if (statementTrace>=1) 
				printf("%d member_declaration Templated forward declaration\n",LT(1)->getLine());
			}
			declaration_specifiers (init_declarator_list)? SEMICOLON {end_of_stmt();}
		|
			// Templated function declaration
			(declaration_specifiers function_declarator[0] SEMICOLON)=>
			{if (statementTrace>=1) 
				printf("%d member_declaration Templated function declaration\n",LT(1)->getLine());
			}
			declaration
		|  
			// Templated function definition
			(declaration_specifiers function_declarator[1] LCURLY)=> 
			{if (statementTrace>=1) 
				printf("%d member_declaration Templated function definition\n",LT(1)->getLine());
			}
			function_definition
		|
			// Templated constructor declarator
			(	ctor_decl_spec
				{qualifiedItemIsOneOf(qiCtor)}?
				ctor_declarator[0] SEMICOLON
			)=>
			{if (statementTrace>=1) 
				printf("%d member_declaration Templated constructor declarator\n",LT(1)->getLine());
			}
			ctor_decl_spec ctor_declarator[0] SEMICOLON {end_of_stmt();}
		|
			// Templated constructor definition
			// JEL 4/3/96 Added predicate that works once the
			// restriction is added that ctor cannot be virtual
			(ctor_decl_spec {qualifiedItemIsOneOf(qiCtor)}?
			)=>
			{if (statementTrace>=1) 
				printf("%d member_declaration Templated constructor definition\n",LT(1)->getLine());
			}
			ctor_definition
		|
			// Templated operator function
			{if (statementTrace>=1) 
				printf("%d member_declaration Templated operator function\n",LT(1)->getLine());
			}
			conversion_function_decl_or_def
		|
			// Templated class definition
			{if (statementTrace>=1) 
				printf("%d member_declaration Templated class definition\n",LT(1)->getLine());
			}
			class_head declaration_specifiers (init_declarator_list)? SEMICOLON {end_of_stmt();}
		)
		{endTemplateDeclaration();}
	|
		// Access specifier  
		{if (statementTrace>=1) 
			printf("%d member_declaration Access specifier\n",LT(1)->getLine());
		}
		access_specifier COLON
	|
		// Semicolon
		{if (statementTrace>=1) 
			printf("%d member_declaration Semicolon\n",LT(1)->getLine());
		}
		SEMICOLON {end_of_stmt();}
	|	
		// The next two entries may be used for debugging
		// Use this statement in the source code to turn antlr trace on (See note above)
		"antlrTrace_on" {antlrTrace(true);}
	|
		// Use this statement in the source code to turn antlr trace off (See note above)
		"antlrTrace_off" {antlrTrace(false);}
	)
	;	// end member_declaration

//function_definition
function_definition
	:
	(	// Next line is equivalent to guarded predicate in PCCTS
		// (SCOPE | ID)? => <<qualifiedItemIsOneOf(qiType|qiCtor)>>?
		{( !(LA(1)==SCOPE||LA(1)==ID) || qualifiedItemIsOneOf(qiType|qiCtor) )}?
		declaration_specifiers function_declarator[1]
		(	options{warnWhenFollowAmbig = false;}:
			({lineNo = LT(1)->getLine();} declaration)*	// Possible for K & R definition
			{in_parameter_list = false;}
		)?
		compound_statement
	|	
		function_declarator[1]
		(	options{warnWhenFollowAmbig = false;}:
			({lineNo = LT(1)->getLine();} declaration)*	// Possible for K & R definition
			{in_parameter_list = false;}
		)?
		compound_statement
	)
	{endFunctionDefinition();}
	;

//declaration
declaration
	:	
		("extern" StringLiteral)=>
		linkage_specification
	|	
		simple_declaration
	|	
		using_statement
	;

//linkage_specification
linkage_specification
	:	
		"extern"
		StringLiteral
		(LCURLY (external_declaration)* RCURLY
		|declaration
		)
	;

//class_head
class_head
	:	// Used only by predicates
		("struct"  
		|"union" 
		|"class" 
		)
		(ID	
			(LESSTHAN template_argument_list GREATERTHAN)?
			(base_clause)? 
		)? 
		LCURLY
	;

//declaration_specifiers
declaration_specifiers
	{// Locals
	bool td = false;	// For typedef
	bool fd = false;	// For friend
	StorageClass sc = scInvalid;	// auto,register,static,extern,mutable
	TypeQualifier tq = tqInvalid;	// const,volatile	// aka cv_qualifier See type_qualifier
	TypeSpecifier ts = tsInvalid;	// char,int,double, etc., class,struct,union
	FunctionSpecifier fs = fsInvalid;	// inline,virtual,explicit
	}
	:
	{
	// Global flags to allow for nested declarations
	_td = false;		// For typedef
	_fd = false;		// For friend
	_sc = scInvalid;	// For StorageClass		// auto,register,static,extern,mutable
	_tq = tqInvalid;	// For TypeQualifier	// aka cv_qualifier See type_qualifier
	_ts = tsInvalid;	// For TypeSpecifier
	_fs = fsInvalid;	// For FunctionSpecifier	// inline,virtual,explicit

	}
	(	(options {warnWhenFollowAmbig = false;}
		:	"typedef"	{td=true;}			
		|	"friend"	{fd=true;}
		|	sc = storage_class_specifier	// auto,register,static,extern,mutable
		|	tq = type_qualifier		// const,volatile	// aka cv_qualifier See type_qualifier
		|	fs = function_specifier	// inline,virtual,explicit
		|	("_declspec"|"__declspec") LPAREN ID RPAREN 
		)*
		ts = type_specifier
		(tq = type_qualifier)*		// const,volatile	// aka cv_qualifier See type_qualifier
	)
	{declarationSpecifier(td,fd,sc,tq,ts,fs);}
	;

//storage_class_specifier
storage_class_specifier returns [CPPParser::StorageClass sc = scInvalid]
	:	"auto"		{sc = scAUTO;}
	|	"register"	{sc = scREGISTER;}
	|	"static"	{sc = scSTATIC;}
	|	"extern"	{sc = scEXTERN;}
	|	"mutable"	{sc = scMUTABLE;}
	;
		
//function_specifier
function_specifier returns [CPPParser::FunctionSpecifier fs = fsInvalid]
	:	("inline"|"_inline"|"__inline")	{fs = fsINLINE;}
	|	"virtual"						{fs = fsVIRTUAL;}
	|	"explicit"						{fs = fsEXPLICIT;}
	;

//type_specifier
type_specifier returns [CPPParser::TypeSpecifier ts = tsInvalid]
	{//char *s;
	 TypeQualifier tq = tqInvalid;
	}
	:	
		ts = simple_type_specifier
	;

//simple_type_specifier
simple_type_specifier returns [CPPParser::TypeSpecifier ts = tsInvalid]
	{
	char *s;
	ts = tsInvalid;
	}
	:	(
			{qualifiedItemIsOneOf(qiType|qiCtor)}?
			 s = qualified_type
		|
			("typename"|"enum"|ts = class_specifier) 
			 s = qualified_type
			{declaratorID(s,qiType);}	// This stores typename name in dictionary
		|	
			(	"char"		{ts |= tsCHAR;}
			|	"wchar_t"	{ts |= tsWCHAR_T;}  
			|	"bool"		{ts |= tsBOOL;}
			|	"short"		{ts |= tsSHORT;}
			|	"int"		{ts |= tsINT;}
			|	("_int8"|"__int8")		{ts |= tsINT;}
			|	("_int16"|"__int16")	{ts |= tsINT;}
			|	("_int32"|"__int32")	{ts |= tsLONG;}
			|	("_int64"|"__int64")	{ts |= tsLONG;}
			|	("_w64"|"__w64")		{ts |= tsLONG;}
			|	"long"		{ts |= tsLONG;}
			|	"signed"	{ts |= tsSIGNED;}
			|	"unsigned"	{ts |= tsUNSIGNED;}
			|	"float"		{ts |= tsFLOAT;}
			|	"double"	{ts |= tsDOUBLE;}
			|	"void"		{ts |= tsVOID;}
			)+
		)
	;

//qualified_type
qualified_type returns [char *qit = NULL]
	{
	 char *so = NULL;
	 char qitem01[CPPParser_MaxQualifiedItemSize+1];
	 qitem01[0] = '\0';
	}
	: 
		// JEL 3/29/96 removed this predicate and moved it upwards to
		// simple_type_specifier.  This was done to allow parsing of ~ID to 
		// be a unary_expression, which was never reached with this 
		// predicate on
		// {qualifiedItemIsOneOf(qiType|qiCtor)}?

		so = scope_override 
		{
		 strcpy(qitem01, so);
		}
		id:ID 
		{
		 strcat(qitem01, (id->getText()).data());
		 qit = qitem01;
		}
		(options {warnWhenFollowAmbig = false;}:
		 LESSTHAN template_argument_list GREATERTHAN
		)?
	;

//class_specifier
class_specifier returns [CPPParser::TypeSpecifier ts = tsInvalid]
	:	
		("class"	{ts = tsCLASS;}	
		|"struct"	{ts = tsSTRUCT;}
		|"union"	{ts = tsUNION;}
		)
	;

//type_qualifier
type_qualifier returns [CPPParser::TypeQualifier tq = tqInvalid] // aka cv_qualifier
	:  
		("const"	{tq = tqCONST;} 
		|"volatile"	{tq = tqVOLATILE;}
		)
	;

//class_decl_or_def
class_decl_or_def [FunctionSpecifier fs] 
	{char *saveClass; 
	 char *id;
	 char qid[CPPParser_MaxQualifiedItemSize+1];
	 TypeSpecifier ts = tsInvalid;	// Available for use
	}
	:	
		("class"	{ts = tsCLASS;}	
		|"struct"	{ts = tsSTRUCT;}
		|"union"	{ts = tsUNION;}
		)
		(("_declspec"|"__declspec") LPAREN expression RPAREN)*	// Temp for Evgeniy
		(	id = qualified_id
			{strcpy(qid,id);}
			(options{generateAmbigWarnings = false;}:
				(SEMICOLON|member_declarator)=>
				// Empty 
				{classForwardDeclaration(qid, ts, fs);}	// This stores class name in dictionary
			|
				(base_clause)?
				LCURLY
				{saveClass = enclosingClass; enclosingClass = symbols->strdup(qid);
				 beginClassDefinition(qid, ts);}	// This stores class name in dictionary
				(member_declaration)*
				{endClassDefinition();}
				RCURLY
				{enclosingClass = saveClass;}
			)
		|
			LCURLY
			{saveClass = enclosingClass; enclosingClass = "__anonymous";
			 beginClassDefinition("anonymous", ts);}	// This stores "anonymous" name in dictionary
			(member_declaration)*
			{endClassDefinition();}
			RCURLY
			{enclosingClass = saveClass;}
		)
	;

//base_clause
base_clause
	:	
		COLON base_specifier (COMMA base_specifier)*
	;

//base_specifier
base_specifier
	{char *qt;}
	:	
		(	"virtual" (access_specifier)? qt = qualified_type 
		|	access_specifier ("virtual")? qt = qualified_type
		|	qt = qualified_type
		)
	;

//access_specifier
access_specifier
	:	
		(	"public"
		|	"protected"
		|	"private"
		)
	;

//enum_specifier
enum_specifier
	{
	char *id;
	}
	:	
		"enum"
		(	
			LCURLY enumerator_list RCURLY
		|	
			id = qualified_id
			{beginEnumDefinition(id);}	// This stores id name as an enum type in dictionary
			(LCURLY enumerator_list RCURLY)?
			{endEnumDefinition();}
		)
	;

//enumerator_list
enumerator_list
	:	
		enumerator (COMMA (enumerator)? )*	// Allows comma at end of list
	;

//enumerator
enumerator
	:	
		id:ID (ASSIGNEQUAL constant_expression)?
		{enumElement((id->getText()).data());}	// This stores id name in dictionary
	;

/* This matches a generic qualified identifier ::T::B::foo
 * (including OPERATOR).
 * It might be a good idea to put T::~dtor in here
 * as well, but id_expression in expr.g puts it in manually.
 * Maybe not, 'cause many people use this assuming only A::B.
 * How about a 'qualified_complex_id'?
 */
//qualified_id
qualified_id returns [char *qid = NULL]
	{
	char *so = NULL;
	char *op = NULL;
	char qitem02[CPPParser_MaxQualifiedItemSize+1];
	qitem02[0] = '\0';
	}
	:	
		so =  scope_override
		{
		 strcpy(qitem02, so);
		}
		(	id:ID {strcat(qitem02,(id->getText()).data());}
			((LESSTHAN template_argument_list GREATERTHAN)=>
			  LESSTHAN template_argument_list GREATERTHAN)? // {strcat(qitem02,"<...>");}
		|  
			OPERATOR op=optor
			{strcat(qitem02,"operator"); strcat(qitem02,op);}
		|
			TILDE id_expression		// 1/08/07
		)
		{
		qid = qitem02;
		}
	;

//typeID
typeID
	:	
		{isTypeName((LT(1)->getText()).data())}?
		ID
	;

//init_declarator_list
init_declarator_list
	:	
		member_declarator (COMMA member_declarator)*
	;

//member_declarator
member_declarator
	:	
		((ID)? COLON constant_expression)=>(ID)? COLON constant_expression
	|  
		declarator
		(
			(ASSIGNEQUAL OCTALINT SEMICOLON)=> ASSIGNEQUAL OCTALINT	// The value must be zero (for pure virtual)
		|	
			ASSIGNEQUAL 
			initializer
		|	
			LPAREN expression_list RPAREN
		)?
	;

//initializer
initializer
	:	
		remainder_expression	// assignment_expression
	|	
		LCURLY initializer (COMMA (initializer)? )* RCURLY	// Allows comma at end of list
	;

//declarator
declarator
	:
		(ptr_operator)=> ptr_operator	// AMPERSAND or STAR etc.
		declarator
	|	
		direct_declarator
	;

//direct_declarator
direct_declarator
	{
	char *id;
	CPPParser::TypeQualifier tq;
	}
	:	
		(qualified_id LPAREN (RPAREN|declaration_specifiers) )=>	// Must be function declaration
		id = qualified_id
		{if (_td==true)       // This statement is a typedef   
			declaratorID(id,qiType);
		 else
			declaratorID(id,qiFun);
		}
		LPAREN {declaratorParameterList(0);}
		(parameter_list)?
		RPAREN {declaratorEndParameterList(0);}
		(tq = type_qualifier)*
		(exception_specification)?
	|	
		(qualified_id LPAREN qualified_id)=>	// Must be class instantiation
		id = qualified_id
		{declaratorID(id,qiVar);}
		LPAREN
		expression_list
		RPAREN
	|
		(qualified_id LSQUARE)=>	// Must be array declaration
		id = qualified_id
		{if (_td==true)       // This statement is a typedef   
			declaratorID(id,qiType);	// This statement is a typedef
		 else
			declaratorID(id,qiVar);
		 is_address = false; is_pointer = false;
		}
		(options {warnWhenFollowAmbig = false;}:
		 LSQUARE (constant_expression)? RSQUARE)+
		{declaratorArray();}
	|
		(qualified_id RPAREN LPAREN)=>	// Must be function declaration (see function_direct_declarator)
		id = qualified_id
		{if (_td==true)       // This statement is a typedef   
			declaratorID(id,qiType);	// This statement is a typedef
		 else
			declaratorID(id,qiFun);
		 is_address = false; is_pointer = false;
		}
	|
		id = qualified_id
		{
		if (_td==true)
			{
			declaratorID(id,qiType);	// This statement is a typedef
			}
		 else
			declaratorID(id,qiVar);
		 is_address = false; is_pointer = false;
		}
	|	
		LPAREN declarator RPAREN 
		(options {warnWhenFollowAmbig = false;}:
		 declarator_suffix)? // DW 1/9/04 declarator_suffix made optional as failed on line 2956 in metrics.i
	;							// According to the grammar a declarator_suffix is not required here

//declarator_suffix
declarator_suffix		// Note: Only used above in direct_declarator
	{CPPParser::TypeQualifier tq;}  
	:
	(	
		//(options {warnWhenFollowAmbig = false;}:
		(LSQUARE (constant_expression)? RSQUARE)+
		{declaratorArray();}
	|	
		{(!((LA(1)==LPAREN)&&(LA(2)==ID))||(qualifiedItemIsOneOf(qiType|qiCtor,1)))}?
		LPAREN {declaratorParameterList(0);}
		(parameter_list)?
		RPAREN {declaratorEndParameterList(0);}
		(tq = type_qualifier)*
		(exception_specification)?
	)
	;

//conversion_function_decl_or_def
conversion_function_decl_or_def
	{CPPParser::TypeQualifier tq;}
	:	
		OPERATOR declaration_specifiers (STAR | AMPERSAND)?	// DW 01/08/03 Use type_specifier here? see syntax
		(LESSTHAN template_parameter_list GREATERTHAN)?
		LPAREN (parameter_list)? RPAREN	
		(tq = type_qualifier)*	// DW 29/07/05 ? changed to *
		(exception_specification)?
		(	compound_statement
		|	SEMICOLON {end_of_stmt();}
		)
	;

 //function_declarator
function_declarator [int definition]
	:	
		(ptr_operator)=> ptr_operator function_declarator[definition]
	|	
		function_direct_declarator[definition]
	;

//function_direct_declarator
function_direct_declarator [int definition] 
	{
	char *q;
	CPPParser::TypeQualifier tq;
	}
	:
		(	// fix prompted by (isdigit)() in xlocnum
			LPAREN 
			declarator
			RPAREN
		|
			q = qualified_id
			{
			declaratorID(q,qiFun);
			}
		)

		{		
#ifdef MYCODE
		if (definition)
			myCode_function_direct_declarator(q);
#endif MYCODE
		}

		LPAREN 
		{
		functionParameterList();
		if (K_and_R == true)
			in_parameter_list = false;
		else
			in_parameter_list = true;
		}
		(parameter_list)? 
		{
		if (K_and_R == true)
	  		in_parameter_list = true;
		else
			in_parameter_list = false;
		}
		RPAREN
		(options{warnWhenFollowAmbig = false;}:
		 tq = type_qualifier)*
		(ASSIGNEQUAL OCTALINT)?	// The value of the octal must be 0
		{functionEndParameterList(definition);}
		(exception_specification)?
	;


//ctor_definition
ctor_definition 
	:
		ctor_head
		ctor_body
		{endConstructorDefinition();}
	;

//ctor_head
ctor_head 
	:
		ctor_decl_spec
		ctor_declarator[1]
	;

//ctor_decl_spec
ctor_decl_spec
	:
		(("inline"|"_inline"|"__inline")|"explicit")*
	;

//ctor_declarator
ctor_declarator[int definition]
	{char *q;}
	: 
		q = qualified_ctor_id
		{declaratorParameterList(definition);}
		LPAREN (parameter_list)? RPAREN
		{declaratorEndParameterList(definition);}
		(exception_specification)?
	;

// This matches a generic qualified identifier ::T::B::foo
// that is satisfactory for a ctor (no operator, no trailing <>)
qualified_ctor_id returns [char *q = NULL]
	{
	char *so;
	char qitem03[CPPParser_MaxQualifiedItemSize+1];
	qitem03[0] = '\0';
	}
	: 
		so = scope_override
		{strcpy(qitem03, so);}
		id:ID	// DW 24/05/04 Note. Neither Ctor or Dtor recorded in dictionary
		{strcat(qitem03,(id->getText()).data());
		q = qitem03;
		//printf("CPP_parser.g qualified_ctor_id q %s\n",q);
		} 
	;

//ctor_body
ctor_body
	:
		(ctor_initializer)?
		compound_statement
	;

//ctor_initializer
ctor_initializer
	:
		COLON superclass_init (COMMA superclass_init)*
	;

//superclass_init
superclass_init
	{char *q;} 
	: 
		q = qualified_id LPAREN (expression_list)? RPAREN
	;

//dtor_head
dtor_head[int definition]
	:
		dtor_decl_spec
		dtor_declarator[definition]
	;

//dtor_decl_spec
dtor_decl_spec
	:
		(("inline"|"_inline"|"__inline")|"virtual")*
	;

//dtor_declarator
dtor_declarator[int definition]
	{char *s;}
	:	
		s = scope_override
		TILDE ID
		{declaratorParameterList(definition);}
		LPAREN ("void")? RPAREN
		{declaratorEndParameterList(definition);}
		(exception_specification)?
	;

//dtor_body
dtor_body
	:
		compound_statement
		{endDestructorDefinition();}
	;

//parameter_list
parameter_list
	:	
		parameter_declaration_list (ELLIPSIS)?
	;

//parameter_declaration_list
parameter_declaration_list
	:	
		(parameter_declaration (COMMA parameter_declaration)* )
	;

//parameter_declaration	(See also template_parameter_declaration)
parameter_declaration
	:	
		{beginParameterDeclaration();}
		(
			{!((LA(1)==SCOPE) && (LA(2)==STAR||LA(2)==OPERATOR)) &&
			 (!(LA(1)==SCOPE||LA(1)==ID) || qualifiedItemIsOneOf(qiType|qiCtor) )}?
			
			declaration_specifiers	// DW 24/3/98 Mods for K & R
			(  
				(declarator)=> declarator        // if arg name given
			| 
				abstract_declarator     // if arg name not given  // can be empty
			)
		|
			(declarator)=> declarator			// DW 24/3/98 Mods for K & R
		|
			ELLIPSIS
		)
		(ASSIGNEQUAL 
		 remainder_expression // DW 18/4/01 assignment_expression
		)?
	;

//type_id
type_id
	:
		declaration_specifiers abstract_declarator
	;

/* This rule looks a bit weird because (...) can happen in two
 * places within the declaration such as "void (*)()" (ptr to
 * function returning nothing).  However, the () of a function
 * can only occur after having seen either a (abstract_declarator)
 * and not after a [..] or simple '*'.  These are the only two
 * valid () func-groups:
 *    int (*)();     // ptr to func
 *    int (*[])();   // array of ptr to func
 */
//abstract_declarator
abstract_declarator
	:	
		ptr_operator abstract_declarator 
	|	
		(LPAREN abstract_declarator RPAREN (LSQUARE|LPAREN) )=> LPAREN abstract_declarator RPAREN
		(options {warnWhenFollowAmbig = false;}:
		abstract_declarator_suffix)
	|	
		(options {warnWhenFollowAmbig = false;}:
		abstract_declarator_suffix)?
	;

//abstract_declarator_suffix
abstract_declarator_suffix
	:	
		(LSQUARE (constant_expression)? RSQUARE)+
		{declaratorArray();}
	|
		LPAREN
		{declaratorParameterList(0);}
		(parameter_list)?
		RPAREN
		{declaratorEndParameterList(0);}
		cv_qualifier_seq
		(exception_specification)?
	;

//exception_specification
exception_specification
	{char *so;}
	:	
		"throw" 
		LPAREN 
		(	(so = scope_override ID (COMMA so = scope_override ID)* )? 
		|	ELLIPSIS
		)
		RPAREN
	;

//template_head
template_head
	:	
		"template"
		LESSTHAN template_parameter_list GREATERTHAN
	;

//template_parameter_list
template_parameter_list
	:	
		{beginTemplateParameterList();}
		template_parameter (COMMA template_parameter)*
		{endTemplateParameterList();}
	;

/* Rule requires >2 lookahead tokens. The ambiguity is resolved 
 * correctly, however. According to the manual "...A template argument
 * that can be interpreted either as a parameter-declaration or a
 * type-argument (because its identifier is the name of an
 * already existing class) is taken as type-argument."
 * Therefore, any "class ID" that is seen on the input, should
 * match the first alternative here (it should be a type-argument).
 */
//template_parameter
template_parameter
	:	
		(options{generateAmbigWarnings = false;}:
		 type_parameter
		|	
		 (parameter_declaration)=>
		  parameter_declaration
		|
		 template_parameter_declaration
		)
	;

//type_parameter
type_parameter
	:
		(	
			("class"|"typename") 
			(id:ID
				{
				templateTypeParameter((id->getText()).data());
				}
				(ASSIGNEQUAL assigned_type_name)?
			)?
		|
			template_head "class" 
			(id2:ID
				{
				templateTypeParameter((id2->getText()).data());
				}
				(ASSIGNEQUAL assigned_type_name)?
			)?
		)
	;

/* This is to allow an assigned type_name in a template parameter
 *	list to be defined previously in the same parameter list,
 *	as type setting is ineffective whilst guessing
 */
//assigned_type_name
assigned_type_name
	{char* qt; TypeSpecifier ts;}
	:
		(options{generateAmbigWarnings = false;}:
			qt = qualified_type abstract_declarator	
		|
			ts = simple_type_specifier abstract_declarator
		)
	;

//template_parameter_declaration	(See also parameter_declaration)
template_parameter_declaration
	:	
		{beginParameterDeclaration();}
		(
			{!((LA(1)==SCOPE) && (LA(2)==STAR||LA(2)==OPERATOR)) &&
			 (!(LA(1)==SCOPE||LA(1)==ID) || qualifiedItemIsOneOf(qiType|qiCtor) )}?
			
			declaration_specifiers	// DW 24/3/98 Mods for K & R
			(  
				(declarator)=> declarator        // if arg name given
			| 
				abstract_declarator     // if arg name not given  // can be empty
			)
		|
			(declarator)=> declarator			// DW 24/3/98 Mods for K & R
		|
			ELLIPSIS
		)
		(ASSIGNEQUAL
		 additive_expression	// DW 04/09/07 because of ambiguity of ">"
		)?
	;

// This rule refers to an instance of a template class or function
//template_id
template_id	// aka template_class_name
	:	
		ID LESSTHAN template_argument_list GREATERTHAN
	;

//template_argument_list
template_argument_list
	:	
		template_argument (COMMA template_argument)*
	;

/* Here assignment_expression was changed to shift_expression to rule out
 *  x< 1<2 > which causes ambiguities. As a result, these can be used only
 *  by enclosing parentheses x<(1<2)>. This is true for x<1+2> ==> bad,
 *  x<(1+2)> ==> ok.
 */
//template_argument
template_argument
	:
		// DW 07/04/05 This predicate only used here if next is SCOPE or ID
		{( !(LA(1)==SCOPE||LA(1)==ID) || qualifiedItemIsOneOf(qiType|qiCtor) )}?
		type_id
	|	
		shift_expression // failed in iosfwd
	;

///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
//////////////////////////////  STATEMENTS ////////////////////////////
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////

//statement_list
statement_list
	:	
		(statement)+
	;

//statement
statement
	{
	lineNo = LT(1)->getLine();
	FunctionSpecifier fs = fsInvalid;	// inline,virtual,explicit
	}
	:
		(	("namespace"|"using")=>
			block_declaration
		|	(("typedef")? class_specifier (qualified_id)? LCURLY)=>
			member_declaration
		|	(declaration_specifiers ((ptr_operator)=>ptr_operator)? qualified_id)=>
			member_declaration
		|	labeled_statement
		|	case_statement
		|	default_statement
		|	expression SEMICOLON {end_of_stmt();}
		|	compound_statement
		|	selection_statement
		|	iteration_statement
		|	jump_statement
		|	SEMICOLON {end_of_stmt();}
		|	try_block
		|	throw_statement
			// The next two entries may be used for debugging
			// Use this statement in the source code to turn antlr trace on (See note above)
		|	"antlrTrace_on" {antlrTrace(true);}
			// Use this statement in the source code to turn antlr trace off (See note above)
		|	"antlrTrace_off" {antlrTrace(false);}
		)
	;

//block_declaration
block_declaration
	:	simple_declaration
	|	namespace_alias_definition
	|	using_statement
	;

//simple_declaration
simple_declaration
	:
		declaration_specifiers (init_declarator_list)? SEMICOLON {end_of_stmt();}
	;

//labeled_statement
labeled_statement
	:	
		ID COLON statement
	;

//case_statement
case_statement
	:	"case"
		constant_expression COLON statement
	;

//default_statement
default_statement
	:	
		"default" COLON statement
	;

//compound_statement
compound_statement
	:	
		LCURLY 
		{end_of_stmt();
		 enterNewLocalScope();
		}
		(statement_list)?
		RCURLY 
		{exitLocalScope();}
	;

/* NOTE: cannot remove ELSE ambiguity, but it parses correctly.
 * The warning is removed with the options statement
 */
//selection_statement
selection_statement
	:	
		"if" LPAREN 
		{enterNewLocalScope();}
		condition RPAREN
		statement
		(options {warnWhenFollowAmbig = false;}:
		 "else" statement)?
		{exitLocalScope();}
	|	
		"switch" LPAREN
		{enterNewLocalScope();}
		condition RPAREN statement
		{exitLocalScope();}
	;

//iteration_statement
iteration_statement
	:	
		"while"	LPAREN
		{enterNewLocalScope();}
		condition RPAREN 
		statement  
		{exitLocalScope();}
	|	
		"do" 
		{enterNewLocalScope();}
		statement "while"
		LPAREN expression RPAREN 
		{exitLocalScope();}
		SEMICOLON {end_of_stmt();} 
	|	
		"for" LPAREN
		{enterNewLocalScope();}
		(	(declaration)=> declaration 
		|	(expression)? SEMICOLON {end_of_stmt();}
		)
		(condition)? SEMICOLON {end_of_stmt();}
		(expression)?
		RPAREN statement	 
		{exitLocalScope();}
	;

//condition
condition
	:
		(	(declaration_specifiers declarator ASSIGNEQUAL)=> 
			 declaration_specifiers declarator ASSIGNEQUAL remainder_expression
		|	expression
		)
	;

//jump_statement
jump_statement
	:	
		(	"goto" ID SEMICOLON {end_of_stmt();}
		|	"continue" SEMICOLON {end_of_stmt();}
		|	"break" SEMICOLON {end_of_stmt();}
		|	// DW 16/05/03 May be problem here if return is followed by a cast expression 
			"return" {in_return = true;}
			(	options{warnWhenFollowAmbig = false;}:
				(LPAREN {(qualifiedItemIsOneOf(qiType) )}? ID RPAREN)=> 
				LPAREN ID RPAREN (expression)?	// This is an unsatisfactory fix for problem in xstring re "return (allocator);"
												//  and in xlocale re return (_E)(_Tolower((unsigned char)_C, &_Ctype));
				//{printf("%d CPP_parser.g jump_statement Return fix used\n",lineNo);}
			|	expression 
			)?	SEMICOLON {in_return = false,end_of_stmt();} 
		)
	;

//try_block
try_block
	:	
		"try" compound_statement (handler)*
	;

//handler
handler
	:	
		"catch"
		{exceptionBeginHandler();}
		{declaratorParameterList(1);}
		LPAREN exception_declaration RPAREN
		{declaratorEndParameterList(1);}
		compound_statement
		{exceptionEndHandler();}
	;

//exception_declaration
exception_declaration
	:	
		parameter_declaration_list
	;

/* This is an expression of type void according to the ARM, which
 * to me means "statement"; it removes some ambiguity to put it in
 * as a statement also.
 */
//throw_statement
throw_statement
	:	
		"throw" (assignment_expression) ? SEMICOLON { end_of_stmt();}
	;

//using_statement
using_statement
	{char *qid;}
	:		
		"using"
		("namespace" qid = qualified_id		// Using-directive
		|("typename")? qid = qualified_id	// Using-declaration
		)
		SEMICOLON {end_of_stmt();}
	;

///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
//////////////////////////////  EXPRESSIONS ///////////////////////////
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////

// Same as expression_list
//expression
expression
	{
	lineNo = LT(1)->getLine();
	}
	:	
		assignment_expression (COMMA assignment_expression)*
	;

// right-to-left for assignment op
//assignment_expression
assignment_expression
	:	
		conditional_expression
		(	
			(ASSIGNEQUAL|TIMESEQUAL|DIVIDEEQUAL|MINUSEQUAL|PLUSEQUAL
			|MODEQUAL|SHIFTLEFTEQUAL|SHIFTRIGHTEQUAL|BITWISEANDEQUAL
			|BITWISEXOREQUAL|BITWISEOREQUAL
			)
			remainder_expression
		)?
	;

//remainder_expression
remainder_expression
	:
		(	
			(conditional_expression (COMMA|SEMICOLON|RPAREN) )=>
			{assign_stmt_RHS_found += 1;}
			assignment_expression
			{
			if (assign_stmt_RHS_found > 0)
				assign_stmt_RHS_found -= 1;
			else
				{
				fprintf(stderr,"%d warning Error in assign_stmt_RHS_found = %d\n",
					lineNo,assign_stmt_RHS_found);
				fprintf(stderr,"Press return to continue\n");
				getchar();
				}
			}
		|	
			assignment_expression
		)
	;

//conditional_expression
conditional_expression
	:	
		logical_or_expression
		(QUESTIONMARK expression COLON conditional_expression)?
	;

//constant_expression
constant_expression
	:	
		conditional_expression
	;

//logical_or_expression
logical_or_expression
	:	
		logical_and_expression (OR logical_and_expression)* 
	;

//logical_and_expression
logical_and_expression
	:	
		inclusive_or_expression (AND inclusive_or_expression)* 
	;

//inclusive_or_expression
inclusive_or_expression
	:	
		exclusive_or_expression (BITWISEOR exclusive_or_expression)*
	;

//exclusive_or_expression
exclusive_or_expression
	:	
		and_expression (BITWISEXOR and_expression)*
	;

//and_expression
and_expression
	:	
		equality_expression (AMPERSAND equality_expression)*
	;

//equality_expression
equality_expression
	:	
		relational_expression ( (NOTEQUAL|EQUAL) relational_expression)*
	;

//relational_expression
relational_expression
	:	
		shift_expression
		(options {warnWhenFollowAmbig = false;}:
			(	LESSTHAN
			|	GREATERTHAN
			|	LESSTHANOREQUALTO
			|	GREATERTHANOREQUALTO
			)
		 shift_expression
		)*
	;

//shift_expression
shift_expression
	:	
		additive_expression ((SHIFTLEFT | SHIFTRIGHT) additive_expression)*
	;

// See comment for multiplicative_expression regarding #pragma
additive_expression
	:	
		multiplicative_expression
		(options{warnWhenFollowAmbig = false;}:
			(PLUS | MINUS) multiplicative_expression
		)*
	;

// ANTLR has trouble dealing with the analysis of the confusing unary/binary
// operators such as STAR, AMPERSAND, PLUS, etc...  
// With the #pragma (now "(options{warnWhenFollowAmbig = false;}:" etc.)
// we simply tell ANTLR to use the "quick-to-analyze" approximate lookahead
// as full LL(k) lookahead will not resolve the ambiguity anyway.  Might
// as well not bother.  This has the side-benefit that ANTLR doesn't go
// off to lunch here (take infinite time to read grammar).
multiplicative_expression
	:	
		pm_expression
		(options{warnWhenFollowAmbig = false;}:
			(STAR|DIVIDE|MOD) pm_expression
		)*
	;

//pm_expression
pm_expression
	:	
		cast_expression ( (DOTMBR|POINTERTOMBR) cast_expression)*
	;

/* The string "( ID" can be either the start of a cast or
 * the start of a unary_expression.  However, the ID must
 * be a type name for it to be a cast.  Since ANTLR can only hoist
 * semantic predicates that are visible without consuming a token,
 * the semantic predicate in rule type_name is not hoisted--hence, the
 * rule is reported to be ambiguous.  I am manually putting in the
 * correctly hoisted predicate.
 *
 * Ack! Actually "( ID" might be the start of "(T(expr))" which makes
 * the first parens just an ordinary expression grouping.  The solution
 * is to look at what follows the type, T.  Note, this could be a
 * qualified type.  Yucko.  I believe that "(T(" can only imply
 * function-style type cast in an expression (...) grouping.
 *
 * We DO NOT handle the following situation correctly at the moment:
 * Suppose you have
 *    struct rusage rusage;
 *    return (rusage.fp);
 *    return (rusage*)p;
 * Now essentially there is an ambiguity here. If rusage is followed by any
 * postix operators then it is an identifier else it is a type name. This
 * problem does not occur in C because, unless the tag struct is attached,
 * rusage is not a type name. However in C++ that restriction is removed.
 * No *real* programmer would do this, but it's in the C++ standard just for
 * fun..
 *
 * Another fun one (from an LL standpoint):
 *
 *   (A::B::T *)v;      // that's a cast of v to type A::B::T
 *   (A::B::foo);    // that's a simple member access
 *
 * The qualifiedItemIs(1) function scans ahead to what follows the
 * final "::" and returns qiType if the item is a type.  The offset of
 * '1' makes it ignore the initial LPAREN; normally, the offset is 0.
 */
//cast_expression
cast_expression 
	:
		(LPAREN type_id RPAREN unary_expression)=>
		 LPAREN type_id RPAREN unary_expression
	|
		// Believe it or not, you can get more than one cast expression in sequence
		(LPAREN type_id RPAREN cast_expression)=>
		 LPAREN type_id RPAREN cast_expression
	|  
		unary_expression	// handles outer (...) of "(T(expr))"
	;

//unary_expression
unary_expression
	:
		(	
			(postfix_expression)=> 
			postfix_expression
		|	
			PLUSPLUS unary_expression
		|	
			MINUSMINUS unary_expression
		|	
			unary_operator cast_expression
		|	
			("sizeof"
			|"__alignof__" 	//Zhaojz 02/02/05 to fix bug 29 (GNU)
			)
			(	(unary_expression)=>
				 unary_expression
			|
				LPAREN type_id RPAREN
			)
		|   
			(SCOPE)?
			(new_expression
			|delete_expression
			)
		)
	;

//postfix_expression
postfix_expression
	{
	 TypeSpecifier ts;
	}
	:
	(	
		options {warnWhenFollowAmbig = false;}:
		// Function-style cast must have a leading type
		{!(LA(1)==LPAREN)}?
		(ts = simple_type_specifier LPAREN RPAREN LPAREN)=>	// DW 01/08/03 To cope with problem in xtree (see test10.i)
		 ts = simple_type_specifier LPAREN RPAREN LPAREN (expression_list)? RPAREN
	|
		{!(LA(1)==LPAREN)}?
		(ts = simple_type_specifier LPAREN)=>
		 ts = simple_type_specifier LPAREN (expression_list)? RPAREN
		// Following put in to allow for the above being a constructor as shown in test_constructors_destructors.cpp
		(DOT postfix_expression)?
	|  
		primary_expression
		(options {warnWhenFollowAmbig = false;}:
        	LSQUARE expression RSQUARE
		|	
			LPAREN (expression_list)? RPAREN 
		|	(DOT|POINTERTO) ("template")? id_expression
		|	PLUSPLUS 
		|	MINUSMINUS
		)*
	|
		("dynamic_cast"|"static_cast"|"reinterpret_cast"|"const_cast")
		LESSTHAN ("const")? ts = type_specifier (ptr_operator)? GREATERTHAN
		LPAREN expression RPAREN
	|
		"typeid" 
		LPAREN ((type_id)=>type_id|expression) RPAREN
		( (DOT|POINTERTO) postfix_expression)?
	)
	;

//primary_expression
primary_expression
	:	id_expression
	|	literal
	|	"this"
	|	LPAREN expression RPAREN
	;

//id_expression
id_expression 
	{
	char *s;
	}
	:
		(	s = qualified_id 
		)
	;

//literal
literal
	:	OCTALINT
	|	DECIMALINT
	|	HEXADECIMALINT
	|	CharLiteral
	|	WCharLiteral
	|	(StringLiteral|WStringLiteral)+
	|	FLOATONE
	|	FLOATTWO
	|	"true"
	|	"false"
	;

//unary_operator
unary_operator
	:	AMPERSAND
	|	STAR
	|	PLUS
	|	MINUS
	|	TILDE
	|	NOT
	;

/* JEL The first ()? is used to resolve "new (expr) (type)" because both
 * (expr) and (type) look identical until you've seen the whole thing.
 *
 * new_initializer appears to be conflicting with function arguments as
 * function arguments can follow a primary_expression.  [This is a full
 * LL(k) versus LALL(k) problem.  Enhancing context by duplication of
 * some rules might handle this.]
 */
//new_expression
new_expression
	:
	(  
		"new"
		(	(LPAREN expression_list RPAREN)=> 
			 LPAREN expression_list RPAREN)?
		(new_type_id|LPAREN type_id RPAREN)
		(options{warnWhenFollowAmbig = false;}:	
		(new_initializer)=> new_initializer)?
	)
	;

//new_initializer
new_initializer
	:	
		LPAREN (expression_list)? RPAREN
	;

//new_type_id
new_type_id
	:	
		declaration_specifiers 
		(options {warnWhenFollowAmbig = false;}:
			new_declarator 
		)?
	;

//new_declarator
new_declarator
	:	 
		ptr_operator
		(options {warnWhenFollowAmbig = false;}:
		new_declarator)?
	|	
		direct_new_declarator
	;

/* The "[expression]" construct conflicts with the "new []" construct
 * (and possibly others).  We used approximate lookahead for the "new []"
 * construct so that it would not try to compute full LL(2) lookahead.
 * Here, we use #pragma approx again because anytime we see a [ followed
 * by token that can begin an expression, we always want to loop.
 * Approximate lookahead handles this correctly.  In fact, approximate
 * lookahead is the same as full lookahead when all but the last lookahead
 * depth are singleton sets; e.g., {"["} followed by FIRST(expression).
 */
//direct_new_declarator
direct_new_declarator
	:
		(options {warnWhenFollowAmbig = false;}:
			LSQUARE expression RSQUARE
		)+
	;

//ptr_operator
ptr_operator
	{char *s;}
	:	
		(	AMPERSAND 	{is_address = true;}
		|	("_cdecl"|"__cdecl") 
		|	("_near"|"__near") 
		|	("_far"|"__far") 
		|	"__interrupt" 
		|	("pascal"|"_pascal"|"__pascal") 
		|	("_stdcall"|"__stdcall") 
		|	(s = scope_override STAR cv_qualifier_seq)=>
			 s = scope_override STAR {is_pointer = true;} cv_qualifier_seq
		)	
   ;

// Match A::B::*	// May be redundant 14/06/06
//ptr_to_member
ptr_to_member	// Part of ptr_operator in grammar.txt
	{char *s;}
	:
		s = scope_override STAR  {is_pointer = true;} cv_qualifier_seq
	;

// JEL note:  does not use (const|volatile)* to avoid lookahead problems
//cv_qualifier_seq
cv_qualifier_seq
	{CPPParser::TypeQualifier tq;}
	:
		(tq = type_qualifier)*
	;

// Match "(::)A::B::C::(template)" or just "::"
//scope_override
scope_override returns [char *so = NULL]
	{
	char sitem[CPPParser_MaxQualifiedItemSize+1];
	// The above statement must be non static because its calling is nested
	sitem[0] = '\0';
	}
	:
		(SCOPE {strcat(sitem,"::");} )?
		(	options {warnWhenFollowAmbig = false;}:
			(ID LESSTHAN template_argument_list GREATERTHAN SCOPE)=>
			id1:ID {strcat(sitem,(id1->getText()).data());}
			LESSTHAN template_argument_list GREATERTHAN // {strcat(sitem,"<...>");}
			SCOPE{strcat(sitem,"::");}
			("template" {strcat(sitem,"template");})?
		|	
			id2:ID {strcat(sitem,(id2->getText()).data());}
			SCOPE {strcat(sitem,"::");}
			("template" {strcat(sitem,"template");})?
		)*
		{
		 so = sitem;
		}
	;

//delete_expression
delete_expression
	:	
		"delete" (LSQUARE RSQUARE)? cast_expression
	;

// Same as expression
//expression_list
expression_list
	:	
		assignment_expression (COMMA assignment_expression)*
	;

//optor
optor returns [char* s=NULL]
	{
	char sitem[CPPParser_MaxQualifiedItemSize+1];
	sitem[0]='\0';
	TypeSpecifier ts=tsInvalid;
	char *opitem;
	}
	:	
		(	"new" {strcat(sitem," new");}
			(options {warnWhenFollowAmbig = false;}:
				LSQUARE RSQUARE  {strcat(sitem,"[]");} )?
		|   
			"delete" {strcat(sitem," delete");}
			(options {warnWhenFollowAmbig = false;}:
				LSQUARE RSQUARE  {strcat(sitem,"[]");} )?
		|	
			LPAREN RPAREN  {strcat(sitem,"()");}
		|	
			LSQUARE RSQUARE  {strcat(sitem,"[]");}
		|
			{strcat(sitem,(LT(1)->getText()).data());}
			optor_simple_tokclass
		|
			{strcat(sitem,"type-specifier()");}
			ts = type_specifier LPAREN RPAREN
		)
		{
		s = sitem;
		}
	;

// optor_simple_tokclass
optor_simple_tokclass
	:
    (PLUS|MINUS|STAR|DIVIDE|MOD|BITWISEXOR|AMPERSAND|BITWISEOR|TILDE|NOT|
	 SHIFTLEFT|SHIFTRIGHT|
	 ASSIGNEQUAL|TIMESEQUAL|DIVIDEEQUAL|MODEQUAL|PLUSEQUAL|MINUSEQUAL|
	 SHIFTLEFTEQUAL|SHIFTRIGHTEQUAL|BITWISEANDEQUAL|BITWISEXOREQUAL|BITWISEOREQUAL|
	 EQUAL|NOTEQUAL|LESSTHAN|GREATERTHAN|LESSTHANOREQUALTO|GREATERTHANOREQUALTO|OR|AND|
	 PLUSPLUS|MINUSMINUS|COMMA|POINTERTO|POINTERTOMBR
	)
	;

{
// Possibility of global stuff in the lexer cpp file

bool in_user_file_deferred = false;	// used to record first detection of user file

int deferredLineCount = 0;	// Used to accumulate line numbers in comments etc.

char principal_file[128];	// Path and name of user file set on reading the first preprocessor #line directive
int principal_line = 0;		// principal file's line number
int principal_last_set = 0; // where principal file's line number was last set

char current_included_file[128];	// Path and name of current include file
int include_line = 0; // include file's line number
int include_last_set = 0; // where included file's line number was last set

}

class CPPLexer extends Lexer;

options
	{
	k = 3;
	exportVocab = STDC;
	testLiterals = true;
	}

// DW 4/11/02 put in to support manual hoisting
tokens
	{
	OPERATOR = "operator";
	}

{
void deferredNewline() 
	{
	deferredLineCount++;	// Declared and initialised in main.cpp (Not true!)
	}

void newline() 
	{
	for (;deferredLineCount>0;deferredLineCount--)
	    {
		CharScanner::newline();
		}
    CharScanner::newline();
    }

// for processing #line .... lines (see note above)
void process_line_directive(const char *includedFile, const char *includedLineNo)
	{
	// See global interface variables above
	// Working variables
	static int line, result;
	static bool principal_file_set = false;
	static int x;
	// Extract included file line no.
	result = sscanf(includedLineNo, "%d \n", &line);

	//printf("CPPLexer line directive on line %d\n",lineNo);
	// remove first " from file path+name by shifting all characters left
	for(x=1;includedFile[x]!='"';x++)
		{
		current_included_file[x-1] = includedFile[x];
		}

	// Check path and name are not too long
	if(x>128)
		{
		//
		printf("Path and name of included file too long\n");
		printf("Increase length of current_included_file and\n");
		printf("  principal_file to at least %d characters\n",x);
		printf("Abandon run\n");
		getchar();		    
		}

	// Replace last " from file name with null
	current_included_file[x-1] = NULL;

	// This will occur on reading the first preprocessor #line directive
	if (!principal_file_set)
		{
		strcpy (principal_file, current_included_file);
		principal_file_set = true;
		}

	// check for main file name
	if (strcmp(principal_file, current_included_file) == 0)
		{
		principal_line = line;	// this is line no. shown in line directive
		principal_last_set = CharScanner::getLine();	// This is line no. in preprocessed *.i file
		strcpy(current_included_file, " "); // delete include file name
		in_user_file_deferred = true; // Users's .C or .CPP file (aka principal_file) detected
		}
	else
		// Check that this is a genuine path
		if(current_included_file[1]==':')
			{//printf("main.cpp 222 entered\n");
			//printf("main.cpp 223 %s %s\n",principal_file,current_included_file);
			include_line = line;	// this is line no. shown in line directive
			include_last_set = CharScanner::getLine();	// This is line no. in preprocessed *.i file
			in_user_file_deferred = false; // Header file file detected
			}
	}

}

// Operators:

ASSIGNEQUAL     : '=' ;
COLON           : ':' ;
COMMA           : ',' ;
QUESTIONMARK    : '?' ;
SEMICOLON       : ';' ;
POINTERTO       : "->" ;

// DOT & ELLIPSIS are commented out since they are generated as part of
// the Number rule below due to some bizarre lexical ambiguity shme.
// DOT  :       '.' ;
// ELLIPSIS      : "..." ;

LPAREN          : '(' ;
RPAREN          : ')' ;
LSQUARE         : '[' ;
RSQUARE         : ']' ;
LCURLY          : '{' ;
RCURLY          : '}' ;

EQUAL           : "==" ;
NOTEQUAL        : "!=" ;
LESSTHANOREQUALTO     : "<=" ;
LESSTHAN              : "<" ;
GREATERTHANOREQUALTO  : ">=" ;
GREATERTHAN           : ">" ;

DIVIDE          : '/' ;
DIVIDEEQUAL     : "/=" ;
PLUS            : '+' ;
PLUSEQUAL       : "+=" ;
PLUSPLUS        : "++" ;
MINUS           : '-' ;
MINUSEQUAL      : "-=" ;
MINUSMINUS      : "--" ;
STAR            : '*' ;
TIMESEQUAL      : "*=" ;
MOD             : '%' ;
MODEQUAL        : "%=" ;
SHIFTRIGHT      : ">>" ;
SHIFTRIGHTEQUAL : ">>=" ;
SHIFTLEFT       : "<<" ;
SHIFTLEFTEQUAL  : "<<=" ;

AND            : "&&" ;
NOT            : '!' ;
OR             : "||" ;

AMPERSAND       : '&' ;
BITWISEANDEQUAL : "&=" ;
TILDE           : '~' ;
//BITWISEAND      : " & " ;
BITWISEOR       : '|' ;
BITWISEOREQUAL  : "|=" ;
BITWISEXOR      : '^' ;
BITWISEXOREQUAL : "^=" ;

//Zuo: the following tokens are come from cplusplus.g

POINTERTOMBR    : "->*" ;
DOTMBR          : ".*"  ;

SCOPE           : "::"  ;

Whitespace	
	:	
		(	// Ignore space
			Space
		|	// handle newlines
			(	'\r' '\n'	// MS
			|	'\r'		// Mac
			|	'\n'		// Unix 
			)	{newline();}
		|	// handle continuation lines
			(	'\\' '\r' '\n'	// MS
			|	'\\' '\r'		// Mac
			|	'\\' '\n'		// Unix 
			)	{printf("CPP_parser.g continuation line detected on line %d\n",lineNo);
				deferredNewline();}
		)	
		{_ttype = ANTLR_USE_NAMESPACE(antlr)Token::SKIP;}
	;

Comment  
	:	
		"/*"   
		(	{LA(2) != '/'}? '*'
		|	EndOfLine {deferredNewline();}
		|	~('*'| '\r' | '\n')
		)*
		"*/" {_ttype = ANTLR_USE_NAMESPACE(antlr)Token::SKIP;}
	;

CPPComment
	:	
		"//" (~('\n' | '\r'))* EndOfLine
 		{_ttype = ANTLR_USE_NAMESPACE(antlr)Token::SKIP; newline();}                     
	;

PREPROC_DIRECTIVE
	options{paraphrase = "a line directive";}
	:	
		'#' LineDirective
		{_ttype = ANTLR_USE_NAMESPACE(antlr)Token::SKIP; newline();} 
	;

protected 
LineDirective
	:
		("line")?  // this would be for if the directive started "#line"
		(Space)+
		n:Decimal
		(Space)+
		(sl:StringLiteral)
		((Space)+ Decimal)*	// To support cpp flags (GNU)
		{
		process_line_directive((sl->getText()).data(), (n->getText()).data());  // see main()
		}
		EndOfLine
	;

protected  
Space
	:	
			(' '|'\t' {tab();}|'\f')
	;

Pragma
	:	
		('#' "pragma"	(	(EndOfContinuedLine)=>EndOfContinuedLine
						|	~('\r' | '\n')
						)* EndOfLine
		)
		{_ttype = ANTLR_USE_NAMESPACE(antlr)Token::SKIP; newline();}
	;

Error
	:	
		('#' "error"	(	(EndOfContinuedLine)=>EndOfContinuedLine
						|	~('\r' | '\n')
						)* EndOfLine
		)
		{_ttype = ANTLR_USE_NAMESPACE(antlr)Token::SKIP; newline();}
	;

// Literals:

/*
 * Note that we do NOT handle tri-graphs nor multi-byte sequences.
 */

/*
 * Note that we can't have empty character constants (even though we
 * can have empty strings :-).
 */
CharLiteral
	:	
		'\'' ( Escape | UniversalCharacterName | ~('\''|'\\'|'\n'|'\r') ) '\''
	;

WCharLiteral
	:
		'L' CharLiteral
	;

/*
 * Can't have raw imbedded newlines in string constants.  Strict reading of
 * the standard gives odd dichotomy between newlines & carriage returns.
 * Go figure.
 */
StringLiteral
	:	
		'"'
		(	Escape
		|	UniversalCharacterName
		|	~('"'|'\\'|'\n'|'\r')
		)*
		'"'
	;

WStringLiteral
	:
		'L' StringLiteral
	;

protected
EndOfContinuedLine
	:
		(options{generateAmbigWarnings = false;}:
			'\\' '\r' '\n'	// MS
		|	'\\' '\r'		// Mac
		|	'\\' '\n'		// Unix 
		)	{deferredNewline();}
	;

protected
EndOfLine
	:	
		(options{generateAmbigWarnings = false;}:
			"\r\n"  // MS
		|	'\r'    // Mac
		|	'\n'    // Unix
		)
	;

/*
 * Handle the various escape sequences.
 *
 * Note carefully that these numeric escape *sequences* are *not* of the
 * same form as the C language numeric *constants*.
 *
 * There is no such thing as a binary numeric escape sequence.
 *
 * Octal escape sequences are either 1, 2, or 3 octal digits exactly.
 *
 * There is no such thing as a decimal escape sequence.
 *
 * Hexadecimal escape sequences are begun with a leading \x and continue
 * until a non-hexadecimal character is found.
 *
 * No real handling of tri-graph sequences, yet.
 */

protected
Escape  
	:	
		'\\'
		( options{warnWhenFollowAmbig=false;}:
		  'a'
		| 'b'
		| 'f'
		| 'n'
		| 'r'
		| 't'
		| 'v'
		| '"'
		| '\''
		| '\\'
		| '?'
		| ('0'..'3') (options{warnWhenFollowAmbig=false;}: Digit (options{warnWhenFollowAmbig=false;}: Digit)? )?
		| ('4'..'7') (options{warnWhenFollowAmbig=false;}: Digit)?
		| 'x' (options{warnWhenFollowAmbig=false;}: HexadecimalDigit)+ //Digit | 'a'..'f' | 'A'..'F')+
		)
	;

// Numeric Constants: 


protected
Digit
	:	
		'0'..'9'
	;

protected
Decimal
	:	
		('0'..'9')+
	;

protected
LongSuffix
	:	'l'
	|	'L'
	;

protected
UnsignedSuffix
	:	'u'
	|	'U'
	;

protected
FloatSuffix
	:	'f'
	|	'F'
	;

protected
Exponent
	:	
		('e'|'E') ('+'|'-')? (Digit)+
	;

protected
UniversalCharacterName
	:
		"\\u" HexQuad
	|	"\\U" HexQuad HexQuad
	;

protected
HexQuad
	:
		HexadecimalDigit HexadecimalDigit HexadecimalDigit HexadecimalDigit 
	;

protected
HexadecimalDigit
	:
		('0'..'9'|'a'..'f'|'A'..'F')
	;

protected
Vocabulary
	:	
		'\3'..'\377'
	;

Number
	:	
		( (Digit)+ ('.' | 'e' | 'E') )=> 
		(Digit)+
		( '.' (Digit)* (Exponent)? {_ttype = FLOATONE;} //Zuo 3/12/01
		| Exponent                 {_ttype = FLOATTWO;} //Zuo 3/12/01
		)                          //{_ttype = DoubleDoubleConst;}
		(FloatSuffix               //{_ttype = FloatDoubleConst;}
		|LongSuffix                //{_ttype = LongDoubleConst;}
		)?
	|	
		("...")=> "..."            {_ttype = ELLIPSIS;}
	|	
		'.'                        {_ttype = DOT;}
		(	(Digit)+ (Exponent)?   {_ttype = FLOATONE;} //Zuo 3/12/01
                                   //{_ttype = DoubleDoubleConst;}
			(FloatSuffix           //{_ttype = FloatDoubleConst;}
			|LongSuffix            //{_ttype = LongDoubleConst;}
			)?
		)?
	|	
		'0' ('0'..'7')*            //{_ttype = IntOctalConst;}
		(LongSuffix                //{_ttype = LongOctalConst;}
		|UnsignedSuffix            //{_ttype = UnsignedOctalConst;}
		)*                         {_ttype = OCTALINT;}
	|	
		'1'..'9' (Digit)*          //{_ttype = IntIntConst;}
		(LongSuffix                //{_ttype = LongIntConst;}
		|UnsignedSuffix            //{_ttype = UnsignedIntConst;}
		)*                         {_ttype = DECIMALINT;}  
	|	
		'0' ('x' | 'X') (HexadecimalDigit)+ //('a'..'f' | 'A'..'F' | Digit)+
                                   //{_ttype = IntHexConst;}
		(LongSuffix                //{_ttype = LongHexConst;}
		|UnsignedSuffix            //{_ttype = UnsignedHexConst;}
		)*                         {_ttype = HEXADECIMALINT;}   
	;

ID
	options {testLiterals = true;}
	:	
		(("asm"|"_asm"|"__asm") Whitespace )=>

		("asm"|"_asm"|"__asm") 
			(EndOfLine {deferredNewline();}
			|Space
			)+
		(
			LPAREN
				(	EndOfLine {deferredNewline();}	
				|	~(')' | '\r' | '\n')
				)*	
			RPAREN {_ttype = ANTLR_USE_NAMESPACE(antlr)Token::SKIP;}
		|
			LCURLY
				(	EndOfLine {deferredNewline();}	
				|	~('}' | '\r' | '\n')
				)*	
			RCURLY {_ttype = ANTLR_USE_NAMESPACE(antlr)Token::SKIP;}
		|
			// Single line asm statement
			(~('(' | ')' | '{' | '}' | '\n' | '\r' | ' ' | '\t' | '\f'))
			(~('(' | ')' | '{' | '}' | '\n' | '\r'))* (EndOfLine {newline();})?
			{_ttype = ANTLR_USE_NAMESPACE(antlr)Token::SKIP;}
		)
	|	
		('a'..'z'|'A'..'Z'|'_')
		('a'..'z'|'A'..'Z'|'_'|'0'..'9')*
	;
